package com.sev.jfa.common.pageinfo;

import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.Validate;

import com.google.common.collect.Lists;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Table;
import com.jfinal.plugin.activerecord.TableMapping;
import com.sev.jfa.config.Consts;


/**
 * @author kool.zhao
 *
 */
public class DynamicPageInfo {

	public static Collection<SearchFilter> genSearchFilter(HttpServletRequest request) {
		Map<String, Object> searchParams = getParametersStartingWith(request, Consts.SEARCH_PREFIX);
		Map<String, SearchFilter> filters = SearchFilter.parse(searchParams);
		return filters.values();
	}
	
	public static PageInfo bySearchFilter(HttpServletRequest request,Class<? extends Model<?>> model,final SearchFilter...searchFilters) {
		Collection<SearchFilter> filters = genSearchFilter(request);
		Set<SearchFilter> set = new HashSet<SearchFilter>(filters);
		for (SearchFilter searchFilter : searchFilters) {
			set.add(searchFilter);
		}
		return bySearchFilter(request, model, set);
	}
	
	public static PageInfo bySearchFilter(HttpServletRequest request,Class<? extends Model<?>> model,final Collection<SearchFilter> searchFilters){
		PageInfo pageInfo = new PageInfo();
		pageInfo.setPageNumber(toInt(request.getParameter("pageNumber"),1));
        pageInfo.setPageSize(toInt(request.getParameter("pageSize"), PageInfo.DEFAULT_PAGE_SIZE));
        
        final Set<SearchFilter> filterSet = new HashSet<SearchFilter>();
        
        // 数据权限中的filter
        
        // 自定义
 		for (SearchFilter searchFilter : searchFilters) {
 			filterSet.add(searchFilter);
 		}
     		
		Table tableinfo = TableMapping.me().getTable(model);
		List<Object> paras = Lists.newArrayList();
		StringBuilder sqlExceptSelect = new StringBuilder();
		sqlExceptSelect.append("from ").append(tableinfo.getName());
		if (filterSet != null && !filterSet.isEmpty()) {
			sqlExceptSelect.append(" where 1=1 ");
			for (SearchFilter filter : filterSet) {
				String fieldName = filter.getFieldName();
                Object value = filter.getValue();
                if (value == null) {
                    continue;
                }
                
                switch (filter.getOperator()) {
                case EQ:
                	sqlExceptSelect.append(filter.getRelation() + " " + fieldName + " = ? ");
                	paras.add(value);
                	break;
				case LIKE:
					sqlExceptSelect.append(filter.getRelation() + " " + fieldName + " like ? ");
                	paras.add("%" + value + "%");
                	break;
				case NEQ:
                	sqlExceptSelect.append(filter.getRelation() + " " + fieldName + " <> ? ");
                	paras.add(value);
                	break;	
				case GT:
                	sqlExceptSelect.append(filter.getRelation() + " " + fieldName + " > ? ");
                	paras.add(value);
                	break;
				case LT:
                	sqlExceptSelect.append(filter.getRelation() + " " + fieldName + " < ? ");
                	paras.add(value);
                	break;
				case GTE:
                	sqlExceptSelect.append(filter.getRelation() + " " + fieldName + " >= ? ");
                	paras.add(value);
                	break;
				case LTE:
                	sqlExceptSelect.append(filter.getRelation() + " " + fieldName + " <= ? ");
                	paras.add(value);
                	break;
				case NULL:
                	sqlExceptSelect.append(filter.getRelation() + " " + fieldName + " IS NULL ");
                	break;
				case NOTNULL:
                	sqlExceptSelect.append(filter.getRelation() + " " + fieldName + " IS NOT NULL ");
                	break;
                }
                
			}
			
		}
		pageInfo.setParas(paras.toArray(new Object[] {}));
		addSorter(request, pageInfo,sqlExceptSelect);
		pageInfo.setSqlExceptSelect(sqlExceptSelect.toString());
		
		return pageInfo;
	}
	
    private static void addSorter(HttpServletRequest request, PageInfo pageInfo,StringBuilder sqlExceptSelect) {
        String sorterField = request.getParameter("sorterField");
        if (StrKit.notBlank(sorterField)) {
            String sorterDirection = request.getParameter("sorterDirection");
            if (StrKit.isBlank(sorterDirection)) {
                sorterDirection = "desc";
            }
            pageInfo.setSorterField(sorterField);
            pageInfo.setSorterDirection(sorterDirection);
            sqlExceptSelect.append(" order by ").append(sorterField).append(" ").append(sorterDirection);
        }
    }
	
	public static Integer toInt(String value, Integer defaultValue) {
		if (value == null || "".equals(value.trim()))
			return defaultValue;
		if (value.startsWith("N") || value.startsWith("n"))
			return -Integer.parseInt(value.substring(1));
		return Integer.parseInt(value);
	}
	
	/**
	 * 取得带相同前缀的Request Parameters, copy from spring WebUtils.
	 * 
	 * 返回的结果的Parameter名已去除前缀.
	 */
	@SuppressWarnings("rawtypes")
	public static Map<String, Object> getParametersStartingWith(HttpServletRequest request, String prefix) {
		Validate.notNull(request, "Request must not be null");
		Enumeration paramNames = request.getParameterNames();
		Map<String, Object> params = new TreeMap<String, Object>();
		if (prefix == null) {
			prefix = "";
		}
		while ((paramNames != null) && paramNames.hasMoreElements()) {
			String paramName = (String) paramNames.nextElement();
			if ("".equals(prefix) || paramName.startsWith(prefix)) {
				String unprefixed = paramName.substring(prefix.length());
				String[] values = request.getParameterValues(paramName);
				if ((values == null) || (values.length == 0)) {
					// Do nothing, no values found at all.
				} else if (values.length > 1) {
					params.put(unprefixed, values);
				} else {
					params.put(unprefixed, values[0]);
				}
			}
		}
		return params;
	}
	 
}
